/*********************************************************************
* Author         : orbit
* Date           : February 6, 2006
* Last-modified  : February 21, 2006 
* Contact us     : inte2000@163.com,support@winmsg.com
* Web Page       : http://www.winmsg.com/cn/orbit.htm (for Chinese version)
*                  http://www.winmsg.com/orbit.htm (for English version)
**********************************************************************/
#include "stdafx.h"
#include "SplashWnd.h"
#include "Resource.h"

#include "../Common/Localization.h"
#include "../Common/SourceInsight.h"
//#include "../Common/product.h"

//////////////////////////////////////////////////////////////

#pragma  comment (lib, "gdi32.lib")

//////////////////////////////////////////////////////////////

//#include <stdlib.h>

int g_nShadowThick = 4;
int g_nShadowMargin = 4;
BOOL g_bDrawShdow = FALSE;
HBITMAP g_hSplashBmp = NULL;
int nBkgndBmpWidth = 0;
int nBkgndBmpHeight = 0;

DWORD g_dwSplashScreenTimeToLive  = 0;
BOOL  g_bStopSplashOnTimer    = TRUE;
UINT  g_uTimerID = 0;

const COLORREF crText     = RGB(59,126,236); // RGB(150,210,125);

HFONT MakeFont( int CharWidth, int CharHeight )
{
  HFONT hf = CreateFont( CharHeight, CharWidth, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 
    OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
    NULL);
  return hf;
}

// Following function was cut from MFC sources and adapted.
void CenterWindow( HWND m_hWnd )
{
  ASSERT(::IsWindow(m_hWnd));

  // determine owner window to center against
  DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  HWND hWndCenter = NULL;

  {
    if (dwStyle & WS_CHILD)
      hWndCenter = ::GetParent(m_hWnd);
    else
      hWndCenter = ::GetWindow(m_hWnd, GW_OWNER);
  }

  // get coordinates of the window relative to its parent
  RECT rcDlg;
  ::GetWindowRect( m_hWnd, &rcDlg );
  RECT rcArea;
  RECT rcCenter;
  HWND hWndParent;
  if (!(dwStyle & WS_CHILD))
  {
    // don't center against invisible or minimized windows
    if (hWndCenter != NULL)
    {
      DWORD dwStyle = ::GetWindowLong(hWndCenter, GWL_STYLE);
      if (!(dwStyle & WS_VISIBLE) || (dwStyle & WS_MINIMIZE))
        hWndCenter = NULL;
    }

    MONITORINFO mi;
    mi.cbSize = sizeof(mi);

    // center within appropriate monitor coordinates
    if (hWndCenter == NULL)
    {
      HWND hwDefault = m_hWnd;

      GetMonitorInfo(MonitorFromWindow(hwDefault, MONITOR_DEFAULTTOPRIMARY), &mi);
      rcCenter = mi.rcWork;
      rcArea = mi.rcWork;
    }
    else
    {
      ::GetWindowRect(hWndCenter, &rcCenter);
      GetMonitorInfo(MonitorFromWindow(hWndCenter, MONITOR_DEFAULTTONEAREST), &mi);
      rcArea = mi.rcWork;
    }
  }
  else
  {
    // center within parent client coordinates
    hWndParent = ::GetParent(m_hWnd);
    ASSERT(::IsWindow(hWndParent));

    ::GetClientRect(hWndParent, &rcArea);
    ASSERT(::IsWindow(hWndCenter));
    ::GetClientRect(hWndCenter, &rcCenter);
    ::MapWindowPoints(hWndCenter, hWndParent, (POINT*)&rcCenter, 2);
  }

  int rcDlg_Width = rcDlg.right - rcDlg.left;
  int rcDlg_Height = rcDlg.bottom - rcDlg.top;

  // find dialog's upper left based on rcCenter
  int xLeft = (rcCenter.left + rcCenter.right) / 2 - rcDlg_Width / 2;
  int yTop = (rcCenter.top + rcCenter.bottom) / 2 - rcDlg_Height / 2;

  // if the dialog is outside the screen, move it inside
  if (xLeft < rcArea.left)
    xLeft = rcArea.left;
  else if (xLeft + rcDlg_Width > rcArea.right)
    xLeft = rcArea.right - rcDlg_Width;

  if (yTop < rcArea.top)
    yTop = rcArea.top;
  else if (yTop + rcDlg_Height > rcArea.bottom)
    yTop = rcArea.bottom - rcDlg_Height;

  // map screen coordinates to child coordinates
  ::SetWindowPos( m_hWnd, NULL, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}

void OnPaint( HWND hWnd )
{
  PAINTSTRUCT ps;
  HDC   hdc = NULL;
  RECT  rt;

  hdc = BeginPaint(hWnd, &ps);

  GetClientRect(hWnd, &rt);

  TCHAR szSoftVer[128],szCopyright[128],szWebUrl[128];
  DWORD dwBufSize = SIZEOF_ARRAY(szSoftVer);
  LocLoadString(IDS_SOFTVERNAME, szSoftVer, &dwBufSize );
  dwBufSize = SIZEOF_ARRAY(szCopyright);
  LocLoadString(IDS_COPYRIGHT, szCopyright, &dwBufSize );
  dwBufSize = SIZEOF_ARRAY(szWebUrl);
  LocLoadString(IDS_WEBURL, szWebUrl, &dwBufSize );

//HFONT MakeFont( int CharWidth, int CharHeight )
  HDC hMemDC = CreateCompatibleDC(hdc);
  HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC,g_hSplashBmp);
  SetBkMode(hMemDC, TRANSPARENT);
  SetTextColor(hMemDC,RGB(200,128,255));
  TextOut(hMemDC,2,2,szSoftVer,lstrlen(szSoftVer));
  SetTextColor(hMemDC,RGB(0,0,255));
  TextOut(hMemDC,90,160,szWebUrl,lstrlen(szWebUrl));

  int nBlock = nBkgndBmpHeight / 10;

  int mm;
  for(int i = 0; i < nBlock; i++)
  {
    for(int j = 0; j < 10; j++)
    {
      mm = j * nBlock + i;
      StretchBlt(hdc,rt.left + 1,rt.top + 1 + mm,nBkgndBmpWidth,1,hMemDC,0,mm,nBkgndBmpWidth,1,SRCCOPY);
    }
    Sleep(20);
  }
  BitBlt(hdc,rt.left + 1,rt.top + 1,nBkgndBmpWidth,nBkgndBmpHeight,hMemDC,0,0,SRCCOPY);
  SelectObject(hMemDC, hOldBmp);
  DeleteDC(hMemDC);

  EndPaint(hWnd, &ps);
}

void OnEraseBkgnd(HWND hWnd, HDC hDC)
{
  RECT rcWnd;
  GetClientRect(hWnd,&rcWnd);

  if(g_bDrawShdow)
  {
    HPEN hPen = CreatePen(PS_SOLID,1,RGB(0,0,255));
    HPEN hOldPen = (HPEN)SelectObject(hDC,hPen);
    HBRUSH hOldBr = (HBRUSH)SelectObject(hDC,GetStockObject(NULL_BRUSH));
    Rectangle(hDC,rcWnd.left,rcWnd.top,rcWnd.right - g_nShadowThick,rcWnd.bottom - g_nShadowThick);
    SelectObject(hDC,hOldBr);
    SelectObject(hDC,hOldPen);
    DeleteObject(hPen);

    static UINT uColorIdx[4] = { COLOR_3DDKSHADOW, COLOR_3DSHADOW, COLOR_3DSHADOW, COLOR_3DFACE };
    for(int i = 0; i < g_nShadowThick; i++)
    {
      HPEN hShadowPen = CreatePen(PS_SOLID,1,GetSysColor(uColorIdx[i]));
      hOldPen = (HPEN)SelectObject(hDC,hShadowPen);
      MoveToEx(hDC,rcWnd.left + g_nShadowMargin,rcWnd.bottom - g_nShadowThick + i,NULL);
      LineTo(hDC,rcWnd.right - g_nShadowThick + i,rcWnd.bottom - g_nShadowThick + i);
      MoveToEx(hDC,rcWnd.right - g_nShadowThick + i,rcWnd.top - g_nShadowMargin + i,NULL);
      LineTo(hDC,rcWnd.right - g_nShadowThick + i,rcWnd.bottom - g_nShadowThick + i);
      SelectObject(hDC,hOldPen);
      DeleteObject(hShadowPen);
    }

  }
  else
  {
    HPEN hPen = CreatePen(PS_SOLID,1,RGB(0,0,255));
    HPEN hOldPen = (HPEN)SelectObject(hDC,hPen);
    HBRUSH hOldBr = (HBRUSH)SelectObject(hDC,GetStockObject(NULL_BRUSH));
    Rectangle(hDC,rcWnd.left,rcWnd.top,rcWnd.right,rcWnd.bottom);
    SelectObject(hDC,hOldBr);
    SelectObject(hDC,hOldPen);
    DeleteObject(hPen);
  }
}

BOOL OnCreate(HWND hWnd)
{
  if(g_bDrawShdow)
  {
    RECT  rt;
    GetClientRect(hWnd, &rt);
    HRGN hWndRgn = CreateRectRgn(rt.left,rt.top,rt.right - g_nShadowThick,rt.bottom - g_nShadowThick);
    HRGN hRgnBottom = CreateRectRgn(rt.left + g_nShadowMargin,rt.bottom - g_nShadowThick + 1, rt.right, rt.bottom);
    HRGN hRgnRight = CreateRectRgn(rt.right - g_nShadowThick + 1,rt.top + 1, rt.right, rt.bottom);
    CombineRgn(hWndRgn,hWndRgn,hRgnBottom,RGN_OR);
    CombineRgn(hWndRgn,hWndRgn,hRgnRight,RGN_OR);
    DeleteObject(hRgnBottom);
    DeleteObject(hRgnRight);
    
    SetWindowRgn(hWnd,hWndRgn,FALSE);
  }
  
  g_uTimerID = SetTimer(hWnd, 0x01, g_dwSplashScreenTimeToLive, NULL);
  if(g_uTimerID == 0)
    return FALSE;

  CenterWindow( hWnd );
  SetCursor( LoadCursor( NULL, MAKEINTRESOURCE(IDC_ARROW) ) );

  return TRUE;
}

void OnTimer(HWND hWnd, UINT uTimerID)
{
  if(uTimerID == g_uTimerID)
  {
    ::DestroyWindow(hWnd);
  }
}

void OnDestroy(HWND hWnd)
{
  if(g_uTimerID != 0)
  {
    KillTimer(hWnd,g_uTimerID);
  }
  if(g_hSplashBmp)
  {
    DeleteObject(g_hSplashBmp);
    g_hSplashBmp = NULL;
  }
}

LRESULT CALLBACK SplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message) 
  {
    case WM_CREATE:
      if(!OnCreate(hWnd))
        return -1;

      break;

    case WM_PAINT:
      OnPaint(hWnd);
      break;
    case WM_ERASEBKGND:
      OnEraseBkgnd(hWnd, (HDC)wParam);
      return 1;

    case WM_LBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_RBUTTONDOWN:
    case WM_KEYDOWN:
      ::DestroyWindow(hWnd);
      break;

    case WM_TIMER:
      OnTimer(hWnd, (UINT)wParam);
      break;

    case WM_DESTROY:
      OnDestroy(hWnd);
      break;

    default:
      return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

void RegisterWndClass( LPCTSTR szWindowClass )
{
  WNDCLASSEX wcex;
  wcex.cbSize     = sizeof(wcex); 
  wcex.style      = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc  = (WNDPROC)SplashWndProc;
  wcex.cbClsExtra   = 0;
  wcex.cbWndExtra   = 0;
  wcex.hInstance    = NULL;
  wcex.hIcon      = NULL;
  wcex.hCursor    = NULL;
  wcex.hbrBackground  = NULL;
  wcex.lpszMenuName = NULL;
  wcex.lpszClassName  = szWindowClass;
  wcex.hIconSm    = NULL;

  RegisterClassEx(&wcex);
}

BOOL CreateSplashScreen(HBITMAP hBkgnd, BOOL bShadow, DWORD milliseconds)
{
  BITMAP bm;
  GetObject(hBkgnd, sizeof(BITMAP), &bm);

  g_hSplashBmp = hBkgnd;
  g_bDrawShdow = bShadow;
  g_dwSplashScreenTimeToLive = milliseconds;
  nBkgndBmpWidth = bm.bmWidth;
  nBkgndBmpHeight = bm.bmHeight;

  int nWndWidth = bm.bmWidth + 2; //Windows frame rect
  int nWndHeight = bm.bmHeight + 2;
  if(g_bDrawShdow)
  {
    nWndWidth += g_nShadowThick;
    nWndHeight += g_nShadowThick;
  }

  HWND hDesktopWnd = GetDesktopWindow();
  RegisterWndClass(lpszSplashWndClass);
  HWND hWndUser = CreateWindowEx(WS_EX_TOPMOST, lpszSplashWndClass,lpszSplashWndText, WS_VISIBLE | WS_POPUP,  0, 0, nWndWidth, nWndHeight, hDesktopWnd, NULL, NULL, NULL);

  ShowWindow(hWndUser, SW_SHOW);

  return TRUE;
}

